<p>When multiple tests differ only by a few hardcoded values they should be refactored as a single "parameterized" test. This reduces the chances of
adding a bug and makes them more readable. Parameterized tests exist in most test frameworks (JUnit, TestNG, etc…​).</p>
<p>The right balance needs of course to be found. There is no point in factorizing test methods when the parameterized version is a lot more complex
than initial tests.</p>
<p>This rule raises an issue when at least 3 tests could be refactored as one parameterized test with less than 4 parameters. Only test methods which
have at least one duplicated statement are considered.</p>
<h2>Noncompliant Code Example</h2>
<p>with JUnit 5</p>
<pre>
import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

public class AppTest
{
    @Test
    void test_not_null1() {  // Noncompliant. The 3 following tests differ only by one hardcoded number.
      setupTax();
      assertNotNull(getTax(1));
    }

    @Test
    void test_not_null2() {
      setupTax();
      assertNotNull(getTax(2));
    }

    @Test
    void test_not_nul3l() {
      setupTax();
      assertNotNull(getTax(3));
    }

    @Test
    void testLevel1() {  // Noncompliant. The 3 following tests differ only by a few hardcoded numbers.
        setLevel(1);
        runGame();
        assertEquals(playerHealth(), 100);
    }

    @Test
    void testLevel2() {  // Similar test
        setLevel(2);
        runGame();
        assertEquals(playerHealth(), 200);
    }

    @Test
    void testLevel3() {  // Similar test
        setLevel(3);
        runGame();
        assertEquals(playerHealth(), 300);
    }
}
</pre>
<h2>Compliant Solution</h2>
<pre>
import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

public class AppTest
{

   @ParameterizedTest
   @ValueSource(ints = {1, 2, 3})
   void test_not_null(int arg) {
     setupTax();
     assertNotNull(getTax(arg));
   }

    @ParameterizedTest
    @CsvSource({
        "1, 100",
        "2, 200",
        "3, 300",
    })
    void testLevels(int level, int health) {
        setLevel(level);
        runGame();
        assertEquals(playerHealth(), health);
    }
}
</pre>
<h2>See</h2>
<ul>
  <li> <a href="https://phauer.com/2019/modern-best-practices-testing-java/#use-parameterized-tests">Modern Best Practices for Testing in Java -
  Philipp Hauer</a> </li>
  <li> <a href="https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests">JUnit 5 documentation - Parameterized tests</a>
  </li>
  <li> <a href="https://www.testwithspring.com/lesson/writing-parameterized-tests-with-junit-4/">Writing Parameterized Tests With JUnit 4</a> </li>
  <li> <a href="https://testng.org/doc/documentation-main.html#parameters">TestNG documentation - Parameters</a> </li>
</ul>

